#include "Application.h"
#include <iostream>
#include <string>
#include "Color.h"
#include <fstream>

using namespace std;

Application::Application(): map(30), curbloc(map)
{
	title = "BlockDrop";
}

Application::~Application()
{
	delete pInput;
	delete pGraphics;
	SDL_DestroyWindow(pWindow);
}

void Application::init()
{


	if (SDL_Init(SDL_INIT_EVERYTHING))
	{
		running = false;
		return;
	}

	pWindow = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320, 600, SDL_WINDOW_SHOWN);

	pGraphics = new Graphics(pWindow);
	pInput = new Input();

	initShapes();
	
	pInput->addKeyDownCallback([&](SDL_Keycode code)
		{
			if (code == SDLK_a || code == SDLK_LEFT)
			{
				curbloc.tryMove(-1);
			}
			else if (code == SDLK_d || code == SDLK_RIGHT)
			{
				curbloc.tryMove(1);
			}
			else if (code == SDLK_w || code == SDLK_UP)
			{
				curbloc.rotate();
			}
			else if (code == SDLK_s || code == SDLK_DOWN)
			{
				while (curbloc.tryDrop());
			}
			return false;
		});

	curbloc.setShape(shapes[int(rand() % shapes.size())]);
	curbloc.setPosition(7, 0);
}

void Application::mainLoop()
{
	int tick = 0;
	while (running)
	{
		pInput->update();

		curbloc.move();
		if (tick++ % 500 == 0)
		{
			
			if (!curbloc.tryDrop())
			{
				bool clearline[30];
				for (int i = 0; i < 30; i++) clearline[i] = false;
				for (auto u : curbloc.getShape().units)
				{
					if (!map.place(curbloc.getX() + u.x, curbloc.getY() + u.y)) 
						running = false;
					if (map.isFull(curbloc.getY() + u.y))
					{
						clearline[int(curbloc.getY() + u.y)] = true;
					}
				}
				for (int i = 0; i < 30; i++)
				{
					if (clearline[i])
					{
						map.clearLine(i);
						score++;
					}
				}
				curbloc.setPosition(7, 0);
				curbloc.setShape(shapes[int(rand() % shapes.size())]);
				SDL_SetWindowTitle(pWindow, (title + " score:" + std::to_string(score)).c_str());
			}
		}

		pGraphics->clear(255, 255, 255, 255);
		
		TetrisMap::drawMap(pGraphics, map, 0, 0);
		auto predict = Block(curbloc);
		while (predict.tryDrop());
		Block::drawBlock(pGraphics, predict, 0, 0, 0xeeeeeeee);
		Block::drawBlock(pGraphics, curbloc, 0, 0, 0);
		pGraphics->drawBox(0, 0, 320, 600);
		pGraphics->present();
	}
}

void Application::initShapes()
{
	int T[4][4] =
	{
		 {0, 1, 0, 0}
		,{1, 1, 1, 0}
		,{0, 0, 0, 0}
		,{0, 0, 0, 0}
	};
	shapes.push_back(Block::newShape(T, 1, 1));

	int L[4][4] =
	{
		 {1, 0, 0, 0}
		,{1, 0, 0, 0}
		,{1, 1, 0, 0}
		,{0, 0 ,0 ,0}
	};
	shapes.push_back(Block::newShape(L, 0, 1));

	int square[4][4] =
	{
		 {1, 1, 0, 0}
		,{1, 1, 0, 0}
		,{0, 0, 0, 0}
		,{0, 0, 0, 0}
	};
	shapes.push_back(Block::newShape(square, 0, 0));

	int J[4][4] =
	{
		 {0, 1, 0, 0}
		,{0, 1, 0, 0}
		,{1, 1, 0, 0}
		,{0, 0, 0, 0}
	};
	shapes.push_back(Block::newShape(J, 1, 1));

	int l[4][4] =
	{
		 {1, 1, 1, 1}
		,{0, 0, 0, 0}
		,{0, 0, 0, 0}
		,{0, 0, 0, 0}
	};
	shapes.push_back(Block::newShape(l, 1, 0));

	int s[4][4] =
	{
		 {0, 1, 1, 0}
		,{1, 1, 0, 0}
		,{0, 0, 0, 0}
		,{0, 0, 0, 0}
	};
	shapes.push_back(Block::newShape(s, 1, 0));

	int z[4][4] =
	{
		 {1, 1, 0, 0}
		,{0, 1, 1, 0}
		,{0, 0, 0, 0}
		,{0, 0, 0, 0}
	};
	shapes.push_back(Block::newShape(z, 1, 0));

	loadModShapes();
}



void Application::loadModShapes()
{
	ifstream input;
	input.open("mod.csv", ios::in);
	if (!input.is_open()) return;
	bool readmode = false;
	int map[4][4];
	int cx, cy;
	int input_status;
	int cntl = 0;
	while (!input.eof())
	{
		string a;
		input >> a;
		//cout << a << endl;
		if (a[0] == '>')
		{
			readmode = true;
			input_status = sscanf_s(a.c_str(), ">,%d,%d,", &cx, &cy);
			continue;
		}

		if (readmode)
		{
			auto _ = sscanf_s(a.c_str(), "%d,%d,%d,%d", &map[cntl][0], &map[cntl][1], &map[cntl][2], &map[cntl][3]);
			cntl++;

			if (cntl > 3)
			{
				if (input_status >= 2) shapes.push_back(Block::newShape(map, cx, cy));
				cntl = 0;
				readmode = false;
			}
		}
	}
}
